home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / TRACE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-07  |  13.9 KB  |  561 lines

  1. /* Packet tracing - top level and generic routines, including hex/ascii
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  *
  6.  * Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
  7.  */
  8. #include "global.h"
  9. #include "ctype.h"
  10. #include "commands.h"
  11. #ifndef MSDOS
  12. #include <time.h>
  13. #endif
  14. #include <stdarg.h>
  15. #include "mbuf.h"
  16. #include "iface.h"
  17. #include "pktdrvr.h"
  18. #include "session.h"
  19. #include "trace.h"
  20. #include "usock.h"
  21.  
  22. #if !defined(_lint)
  23. static char rcsid[] OPTIONAL = "$Id: trace.c,v 1.23 1997/09/07 21:18:28 root Exp root $";
  24. #endif
  25.  
  26. /* this variable and the patch to traceprintf assumes that no kwaits
  27.    will be placed in any of the files used for tracing. */
  28.  
  29. int tracesock;
  30.  
  31.  
  32. #ifdef TRACE
  33. static void ascii_dump (FILE * fp, struct mbuf ** bpp);
  34. static void ctohex (char *buf, int16 c);
  35. static void fmtline (FILE * fp, int16 addr, char *buf, int16 len);
  36. static void hex_dump (FILE * fp, struct mbuf ** bpp, int iftype);
  37. static void showtrace (struct iface * ifp);
  38. static void plain_dump (FILE * fp, register struct mbuf ** bpp);
  39.  
  40. extern int Tracesession;
  41. extern struct session *Trace;
  42.  
  43. #include "slip.h"
  44.  
  45. #ifdef MONITOR
  46. static const char *kissname (struct iface * ifp, struct mbuf * bp, unsigned type);
  47.  
  48.  
  49. static const char *
  50. kissname (struct iface *ifp, struct mbuf *bp, unsigned type)
  51. {
  52. int port;
  53.  
  54.     if (ifp->type != CL_AX25 || type != CL_KISS)
  55.         return ifp->name;
  56.     port = (bp->data[0] & 0xF0) >> 4;
  57.     if (Slip[ifp->xdev].kiss[port] == NULLIF)
  58.         return ifp->name;
  59.     return Slip[ifp->xdev].kiss[port]->name;
  60. }
  61.  
  62. #endif
  63.  
  64.  
  65. int
  66. dostrace (int argc, char *argv[], void *p OPTIONAL)
  67. {
  68.     if (Trace == NULLSESSION) {
  69.         if (argc > 1)
  70.             tputs ("Session tracing not available!\007\n");
  71.         argc = 0;    /* No session setup, so don't allow turning it on ! */
  72.     }
  73.     return setbool (&Tracesession, "Trace to session", argc, argv);
  74. }
  75.  
  76.  
  77. /* Redefined here so that programs calling dump in the library won't pull
  78.  * in the rest of the package
  79.  */
  80.  
  81. static char nospace[] = "No space!!\n";
  82.  
  83. static struct tracecmd Tracecmd[] =
  84. {
  85.     { "input",    IF_TRACE_IN,    IF_TRACE_IN },
  86.     { "-input",    0,        IF_TRACE_IN },
  87.     { "output",    IF_TRACE_OUT,    IF_TRACE_OUT },
  88.     { "-output",    0,        IF_TRACE_OUT },
  89.     { "broadcast",    0,        IF_TRACE_NOBC },
  90.     { "-broadcast",    IF_TRACE_NOBC,    IF_TRACE_NOBC },
  91.     { "raw",    IF_TRACE_RAW,    IF_TRACE_RAW },
  92.     { "-raw",    0,        IF_TRACE_RAW },
  93.     { "ascii",    IF_TRACE_ASCII,    IF_TRACE_ASCII | IF_TRACE_HEX },
  94.     { "-ascii",    0,        IF_TRACE_ASCII | IF_TRACE_HEX },
  95.     { "hex",    IF_TRACE_HEX,    IF_TRACE_ASCII | IF_TRACE_HEX },
  96.     { "-hex",    IF_TRACE_ASCII,    IF_TRACE_ASCII | IF_TRACE_HEX },
  97. #ifdef MONITOR
  98. /* borrow a meaningless combination for the new trace type */
  99. #define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
  100.     { "monitor",    IF_TRACE_PLAIN,    IF_TRACE_ASCII | IF_TRACE_HEX },
  101.     { "-monitor",    IF_TRACE_ASCII,    IF_TRACE_ASCII | IF_TRACE_HEX },
  102. #endif
  103.     { "off",    0,        0xffff },
  104.     { NULLCHAR,    0,        0 }
  105. };
  106.  
  107.  
  108.  
  109. void
  110. dump (register struct iface *ifp, int direction, unsigned type, struct mbuf *bp)
  111. {
  112. struct mbuf *tbp;
  113. void (*func) (FILE *, struct mbuf **, int);
  114. int16 size;
  115. time_t timer;
  116. char *cp;
  117.  
  118. #ifdef KISS            /* Let's straighten out this multiport tracing - K5JB */
  119.     if (type == CL_KISS) {    /* I don't think we will see CL_AX25 */
  120.         int port;    /* don't need this but it improves readability */
  121.         struct iface *kifp;
  122.  
  123.         port = (bp->data[0] & 0xF0) >> 4;
  124.         if ((kifp = Slip[ifp->xdev].kiss[port]) != NULLIF)
  125.             ifp = kifp;
  126.     }
  127. #endif
  128.  
  129.     if (ifp == NULL || (ifp->trace & direction) == 0)
  130.         return;        /* Nothing to trace */
  131.  
  132. #ifdef UNIX
  133.     /* need to check if the traced-to session is a "blocking" session */
  134.     if (ifp->trsock != -1 && sm_blocked (Tracesession ? Trace : Command))
  135.         return;
  136. #else
  137.     if (Tracesession) {
  138.         /* Disable trace if this is not Trace-sessions,
  139.              * or when shelled out, and not tracing to file */
  140.         if ((Current != Trace) && (ifp->trfp == stdout))
  141.             return;    /* Nothing to trace */
  142.     } else {
  143.         /* Disable trace on non-command sessions or when shelled out */
  144.         if ((Current != Command) && (ifp->trfp == stdout))
  145.             return;    /* Nothing to trace */
  146.     }
  147. #endif
  148.  
  149.     if (ifp->trsock != -1)
  150.         tracesock = ifp->trsock;
  151.     else if (Tracesession)
  152.         tracesock = Trace->output;
  153.     else
  154.         tracesock = Command->output;
  155.  
  156.     (void) time (&timer);
  157.     cp = ctime (&timer);
  158.     cp[24] = '\0';
  159.  
  160.     switch (direction) {
  161.         case IF_TRACE_IN:
  162.             if ((ifp->trace & IF_TRACE_NOBC)
  163.                 && (Tracef[type].addrtest != NULLFP ((struct iface *, struct mbuf *)))
  164.                 && (*Tracef[type].addrtest) (ifp, bp) == 0)
  165.                 return;    /* broadcasts are suppressed */
  166. #ifdef MONITOR
  167.             if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  168.                 traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
  169.             else
  170. #endif
  171.                 traceprintf (ifp->trfp, "\n%s - %s recv:\n", cp, ifp->name);
  172.             break;
  173.         case IF_TRACE_OUT:
  174. #ifdef MONITOR
  175.             if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  176.                 traceprintf (ifp->trfp, "(%s) ", kissname (ifp, bp, type));
  177.             else
  178. #endif
  179.                 traceprintf (ifp->trfp, "\n%s - %s sent:\n", cp, ifp->name);
  180.             break;
  181.         default:
  182.             break;
  183.     }
  184.     if (bp == NULLBUF || (size = len_p (bp)) == 0) {
  185.         traceprintf (ifp->trfp, "empty packet!!\n");
  186.         return;
  187.     }
  188.     if (type < NCLASS)
  189.         func = Tracef[type].tracef;
  190.     else
  191.         func = NULLVFP ((FILE *, struct mbuf **, int));
  192.  
  193.     (void) dup_p (&tbp, bp, 0, size);
  194.     if (tbp == NULLBUF) {
  195.         traceprintf (ifp->trfp, nospace);
  196.         return;
  197.     }
  198.     if (func != NULLVFP ((FILE *, struct mbuf **, int)))
  199.         (*func) (ifp->trfp, &tbp, 1);
  200. #ifdef MONITOR
  201.     if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  202.         plain_dump (ifp->trfp, &tbp);
  203.     else
  204. #endif
  205.     if (ifp->trace & IF_TRACE_ASCII) {
  206.         /* Dump only data portion of packet in ascii */
  207.         ascii_dump (ifp->trfp, &tbp);
  208.     } else if (ifp->trace & IF_TRACE_HEX) {
  209.         /* Dump entire packet in hex/ascii */
  210.         free_p (tbp);
  211.         (void) dup_p (&tbp, bp, 0, len_p (bp));
  212.         if (tbp != NULLBUF)
  213.             hex_dump (ifp->trfp, &tbp, ifp->type);
  214.         else
  215.             traceprintf (ifp->trfp, nospace);
  216.     }
  217.     free_p (tbp);
  218. }
  219.  
  220.  
  221. /* Dump packet bytes, no interpretation */
  222. void
  223. raw_dump (struct iface *ifp, int direction, struct mbuf *bp)
  224. {
  225. struct mbuf *tbp;
  226.  
  227.     /* Dump entire packet in hex/ascii */
  228.     traceprintf (ifp->trfp, "\n******* raw packet dump (%s %s)\n",
  229.          ((direction & IF_TRACE_OUT) ? "send" : "recv"), ifp->name);
  230.     (void) dup_p (&tbp, bp, 0, len_p (bp));
  231.     if (tbp != NULLBUF)
  232.         hex_dump (ifp->trfp, &tbp, ifp->type);
  233.     else
  234.         traceprintf (ifp->trfp, nospace);
  235.     traceprintf (ifp->trfp, "*******\n");
  236.     free_p (tbp);
  237.     return;
  238. }
  239.  
  240.  
  241. /* Dump an mbuf in hex */
  242. static void
  243. hex_dump (FILE * fp, register struct mbuf **bpp, int iftype)
  244. {
  245. int16 n;
  246. int16 address;
  247. char buf[16];
  248.  
  249.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  250.         return;
  251.  
  252.     address = 0;
  253.     if (iftype == CL_AX25)
  254.         (void) pullup (bpp, (unsigned char *) buf, 1);    /* remove first zero byte */
  255.     while ((n = pullup (bpp, (unsigned char *) buf, sizeof (buf))) != 0) {
  256.         fmtline (fp, address, buf, n);
  257.         address += n;
  258.     }
  259. }
  260.  
  261.  
  262. /* Dump an mbuf in ascii */
  263. static void
  264. ascii_dump (FILE * fp, register struct mbuf **bpp)
  265. {
  266. int c;
  267. register int16 tot;
  268.  
  269.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  270.         return;
  271.  
  272.     tot = 0;
  273.     while ((c = PULLCHAR (bpp)) != -1) {
  274.         if ((tot % 64) == 0)
  275.             traceprintf (fp, "%04x  ", tot);
  276.         traceprintf (fp, "%c", isprint (uchar (c)) ? c : '.');
  277.         if ((++tot % 64) == 0)
  278.             traceprintf (fp, "\n");
  279.     }
  280.     if ((tot % 64) != 0)
  281.         traceprintf (fp, "\n");
  282. }
  283.  
  284.  
  285. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  286.  * translation, e.g.,
  287.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  288.  */
  289. static void
  290. fmtline (FILE * fp, int16 addr, char *buf, int16 len)
  291. {
  292. char line[100];
  293. register char *aptr, *cptr;
  294. register char c;
  295.  
  296.     memset (line, ' ', sizeof (line));
  297.     ctohex (line, (int16) hibyte (addr));
  298.     ctohex (line + 2, (int16) lobyte (addr));
  299.     aptr = &line[6];
  300.     cptr = &line[55];
  301.     while (len-- != 0) {
  302.         c = *buf++;
  303.         ctohex (aptr, (int16) uchar (c));
  304.         aptr += 3;
  305.         c &= 0x7f;
  306.         *cptr++ = isprint (uchar (c)) ? c : '.';
  307.     }
  308.     *cptr++ = '\n';
  309.     *cptr = 0;
  310.     traceprintf (fp, "%s", line);
  311. }
  312.  
  313.  
  314. /* Convert byte to two ascii-hex characters */
  315. static void
  316. ctohex (register char *buf, register int16 c)
  317. {
  318. static char hex[] = "0123456789abcdef";
  319.  
  320.     *buf++ = hex[hinibble (c)];
  321.     *buf = hex[lonibble (c)];
  322. }
  323.  
  324.  
  325. #ifdef MONITOR
  326. /* Dump an mbuf in ascii with newlines but no others. */
  327. /* Actually, we do limited VT100 parsing, since that seems popular here */
  328. static void
  329. plain_dump (FILE * fp, register struct mbuf **bpp)
  330. {
  331. struct mbuf *tmp, **tmpp = &tmp;
  332. int c, esc, nl;
  333.  
  334.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  335.         return;
  336.  
  337.     /* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
  338.     (void) dup_p (&tmp, *bpp, 0, len_p (*bpp));
  339.     nl = 0;
  340.     while ((c = PULLCHAR (tmpp)) != -1) {
  341.         /*
  342.          * Printable characters are okay, as are \n \t \r \b \f \a \E
  343.          * Nulls and other control characters are verboten, as are meta
  344.          * controls.  Meta-printables are accepted, since they may be
  345.          * intended as PC graphics (but don't expect them to dump right
  346.          * from here because I don't decode them.  Maybe someday).
  347.          */
  348.         if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
  349.             (c > 126 && c < 174) || c > 223)
  350.             nl = 1;
  351.     }
  352.     if (nl) {
  353.         ascii_dump (fp, bpp);
  354.         return;
  355.     }
  356.     esc = 0;
  357.     nl = 1;
  358.     while ((c = PULLCHAR (bpp)) != -1) {
  359.         if (c == 0x1B)
  360.             esc = !esc;
  361.         else if (esc == 1 && c == '[')
  362.             esc = 2;
  363.         else if (esc == 1)
  364.             esc = 0;
  365.         else if (esc == 2 && c != ';' && !isdigit (c)) {
  366.             /* handle some common cases? */
  367.             esc = 0;
  368.         } else if (esc == 0 && c == '\r') {
  369.             traceprintf (fp, "\n");
  370.             nl = 1;
  371.         }
  372.         /* safe programming: not everyone *always* agrees on isprint */
  373.         else if (esc == 0 && c != '\n' && (isprint (c) || c == '\t')) {
  374.             traceprintf (fp, "%c", c);
  375.             nl = 0;
  376.         }
  377.     }
  378.     if (!nl)
  379.         traceprintf (fp, "\n");
  380. }
  381.  
  382. #endif
  383.  
  384.  
  385. /* Modify or displace interface trace flags */
  386. int
  387. dotrace (int argc, char *argv[], void *p OPTIONAL)
  388. {
  389. struct iface *ifp;
  390. struct tracecmd *tp;
  391.  
  392.     if (argc < 2) {
  393.         for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
  394.             showtrace (ifp);
  395.         return 0;
  396.     }
  397.     if ((ifp = if_lookup (argv[1])) == NULLIF) {
  398.         tprintf (Badinterface, argv[1]);
  399.         return 1;
  400.     }
  401. #if 0
  402.     if (ifp->port) {
  403.         tprintf ("No trace on this interface - use master.\n");
  404.         return 1;
  405.     }
  406. #endif
  407.     if (argc == 2) {
  408.         showtrace (ifp);
  409.         return 0;
  410.     }
  411.     /* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
  412.     if (argc >= 3) {
  413.         for (tp = Tracecmd; tp->name != NULLCHAR; tp++)
  414.             if (strncmp (tp->name, argv[2], strlen (argv[2])) == 0)
  415.                 break;
  416.         if (tp->name != NULLCHAR)
  417.             ifp->trace = (int16) ((ifp->trace & (~(unsigned)tp->mask)) | (unsigned)tp->val);
  418.         else
  419.             ifp->trace = (int16) htoi (argv[2]);
  420.     }
  421.     /* Always default to stdout unless trace file is given */
  422.     if (ifp->trsock != -1)
  423.         close_s (ifp->trsock);
  424.     ifp->trsock = -1;
  425.     if (ifp->trfp != NULLFILE && ifp->trfp != stdout)
  426.         (void) fclose (ifp->trfp);
  427.     ifp->trfp = stdout;
  428.     if (ifp->trfile != NULLCHAR)
  429.         free (ifp->trfile);
  430.     ifp->trfile = NULLCHAR;
  431.  
  432.     if (argc >= 4) {
  433.         if (argv[3][0] == '!') {
  434.             /* trace to the current output socket ! */
  435.             ifp->trsock = Curproc->output;
  436.             /* make sure stopping trace doesn't kill connection */
  437.             (void) usesock (ifp->trsock);
  438.         } else if ((ifp->trfp = fopen (argv[3], APPEND_TEXT)) == NULLFILE) {
  439.             tprintf ("Can't write to %s\n", argv[3]);
  440.             ifp->trfp = stdout;
  441.         } else {
  442.             ifp->trfile = strdup (argv[3]);
  443.             if (argc >= 5 && tolower(argv[4][0]) == 'u')
  444.                 setbuf (ifp->trfp, NULL);
  445.         }
  446.     }
  447.     showtrace (ifp);
  448.     return 0;
  449. }
  450.  
  451.  
  452. /* Display the trace flags for a particular interface */
  453. static void
  454. showtrace (register struct iface *ifp)
  455. {
  456.     if (ifp == NULLIF)
  457.         return;
  458.     tprintf ("%s:", ifp->name);
  459. #if 0
  460.     if (ifp->port) {
  461.         tprintf (" trace on master interface only.\n");
  462.         return;
  463.     }
  464. #endif
  465.     if (ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)) {
  466.         if (ifp->trace & IF_TRACE_IN)
  467.             tprintf (" input");
  468.         if (ifp->trace & IF_TRACE_OUT)
  469.             tprintf (" output");
  470.  
  471.         if (ifp->trace & IF_TRACE_NOBC)
  472.             tprintf (" - no broadcasts");
  473.  
  474. #ifdef MONITOR
  475.         if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  476.             tprintf (" (Monitoring)");
  477.         else
  478. #endif
  479.         if (ifp->trace & IF_TRACE_HEX)
  480.             tprintf (" (Hex/ASCII dump)");
  481.         else if (ifp->trace & IF_TRACE_ASCII)
  482.             tprintf (" (ASCII dump)");
  483.         else
  484.             tprintf (" (headers only)");
  485.  
  486.         if (ifp->trace & IF_TRACE_RAW)
  487.             tprintf (" Raw output");
  488.  
  489.         if (ifp->trfile != NULLCHAR)
  490.             tprintf (" trace file: %s", ifp->trfile);
  491.         else if (ifp->trsock >= SOCKBASE)
  492.             tprintf (" tracing to socket");
  493.         tprintf ("\n");
  494.     } else
  495.         tprintf (" tracing off\n");
  496. }
  497.  
  498.  
  499. /* shut down all trace files */
  500. void
  501. shuttrace ()
  502. {
  503. struct iface *ifp;
  504.  
  505.     for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
  506.         if (ifp->trsock != -1)
  507.             close_s (ifp->trsock);
  508.         if (ifp->trfp != NULLFILE && ifp->trfp != stdout)
  509.             (void) fclose (ifp->trfp);
  510.         if (ifp->trfile != NULLCHAR)
  511.             free (ifp->trfile);
  512.         ifp->trfile = NULLCHAR;
  513.         ifp->trfp = NULLFILE;
  514.         ifp->trsock = -1;
  515.     }
  516. }
  517.  
  518. #endif /*TRACE*/
  519.  
  520.  
  521. #ifdef PPP
  522. /* Log messages of the form
  523.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  524.  */
  525. #if defined(SCREENSAVER) && defined(UNIX)
  526. extern int16 intrace;
  527. #endif
  528.  
  529. void
  530. trace_log (struct iface *ifp, const char *fmt,...)
  531. {
  532. va_list ap;
  533. char *cp;
  534. time_t t;
  535.  
  536.     if (ifp->trfp == NULLFILE)
  537.         return;
  538.  
  539.     (void) time (&t);
  540.     cp = ctime (&t);
  541.     rip (cp);
  542.     traceprintf (ifp->trfp, "%s", cp);
  543.  
  544.     traceprintf (ifp->trfp, " - ");
  545.     va_start (ap, fmt);            /*lint !e718 !e746 */
  546. #if defined(SCREENSAVER) && defined(UNIX)
  547.     intrace = 1;
  548. #endif
  549.     if (ifp->trfp == stdout)
  550.         (void) usvprintf (tracesock, fmt, ap);
  551.     else
  552.         (void) vfprintf (ifp->trfp, fmt, ap);
  553. #if defined(SCREENSAVER) && defined(UNIX)
  554.     intrace = 0;
  555. #endif
  556.     va_end (ap);
  557.     traceprintf (ifp->trfp, "\n");
  558. }
  559.  
  560. #endif /* PPP */
  561.